package com.usefullc.extinguisher.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.usefullc.common.exception.BizException;
import com.usefullc.common.user.OnlineUserManager;
import com.usefullc.common.util.BeanUtils;
import com.usefullc.common.util.LocalDateTimeUtils;
import com.usefullc.common.util.XlsUtils;
import com.usefullc.extinguisher.domain.FireDevice;
import com.usefullc.extinguisher.domain.FireDeviceAuditRecord;
import com.usefullc.extinguisher.enums.DeviceAuditRecordStatusEnum;
import com.usefullc.extinguisher.mapper.FireDeviceMapper;
import com.usefullc.extinguisher.param.FireDeviceAuditParam;
import com.usefullc.extinguisher.param.FireDeviceParam;
import com.usefullc.extinguisher.query.FireDeviceAuditRecordQuery;
import com.usefullc.extinguisher.query.FireDeviceQuery;
import com.usefullc.extinguisher.vo.FireDeviceExcelVo;
import com.usefullc.extinguisher.vo.FireDeviceVo;
import com.usefullc.extinguisher.vo.QrPrintItemVo;
import com.usefullc.extinguisher.vo.QrPrintPageVo;
import com.usefullc.system.domain.DataDict;
import com.usefullc.system.entity.Pager;
import com.usefullc.system.query.DataDictQuery;
import com.usefullc.system.service.AbstractBizService;
import com.usefullc.system.service.DataDictService;
import com.usefullc.user.domain.User;
import com.usefullc.user.query.UserQuery;
import com.usefullc.user.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;

/**
 * 消防设备服务类
 *
 * @author: 星空
 * @date: 2022-09-08
 */
@Service
public class FireDeviceService extends AbstractBizService<FireDeviceMapper, FireDevice, FireDeviceQuery> {

    @Autowired
    private FireDeviceAuditRecordService fireDeviceAuditRecordService;

    @Autowired
    private UserService userService;

    @Autowired
    private DataDictService dataDictService;

    @Autowired
    private TemplateEngine templateEngine;


    @Value("classpath:xlsTemplate/fireDevice.xls")
    Resource deviceXlsTemplate;

    @Override
    protected QueryWrapper<FireDevice> getQueryWrapper(FireDeviceQuery query) {
        if (StringUtils.isNotEmpty(query.getCode())) {
            String code = query.getCode();
            code = code.replaceAll("–", "-");
            query.setCode(code);
        }
        QueryWrapper<FireDevice> queryWrapper = super.getQueryWrapper(query);
        return queryWrapper;
    }

    public Pager<FireDeviceVo> findVoByPage(FireDeviceQuery query) {
        Pager<FireDevice> page = this.findByPage(query);
        Pager<FireDeviceVo> newPage = new Pager<>(page);
        List<FireDevice> dataList = page.getDataList();
        List<FireDeviceVo> newDataList = new ArrayList<>();
        newPage.setDataList(newDataList);
        for (FireDevice fireDevice : dataList) {
            FireDeviceVo fireDeviceVo = this.entityToVo(fireDevice);
            newDataList.add(fireDeviceVo);
        }
        return newPage;
    }


    public FireDevice findRawByCode(String code) {
        FireDeviceQuery fireDeviceQuery = new FireDeviceQuery();
        fireDeviceQuery.setCode(code);
        FireDevice fireDevice = this.findOne(fireDeviceQuery);
        return fireDevice;
    }

    public FireDeviceVo findByCode(String code) {
        FireDeviceQuery fireDeviceQuery = new FireDeviceQuery();
        fireDeviceQuery.setCode(code);
        FireDevice fireDevice = this.findOne(fireDeviceQuery);
        return this.entityToVo(fireDevice);
    }

    public FireDeviceVo findFullByCode(String code) {
        FireDeviceQuery fireDeviceQuery = new FireDeviceQuery();
        fireDeviceQuery.setCode(code);
        FireDevice fireDevice = this.findOne(fireDeviceQuery);
        return this.entityToFullVo(fireDevice);
    }

    private FireDeviceVo entityToVo(FireDevice fireDevice) {
        FireDeviceVo fireDeviceVo = new FireDeviceVo();
        if(fireDevice == null){
            return fireDeviceVo;
        }
        BeanUtils.beanCopy(fireDevice, fireDeviceVo);
        //审核人
        Long auditUserId = fireDevice.getAuditUserId();
        if (auditUserId != null) {
            User user = userService.findById(auditUserId);
            if(user != null){
                fireDeviceVo.setAuditUserName(user.getUserName());
            }
        }
        if (StringUtils.isNotEmpty(fireDevice.getPosition())) {
            List<String> positionTextList = new ArrayList<>();
            List<String> positionCodeList = new ArrayList<>();
            DataDict dataDict = dataDictService.getByCode(fireDevice.getPosition());
            while (dataDict != null) {
                positionTextList.add(dataDict.getName());
                positionCodeList.add(dataDict.getCode());
                dataDict = dataDictService.findById(dataDict.getParentId());
            }
            if (positionTextList.size() > 0) {
                Collections.reverse(positionTextList);
                positionTextList.remove(0);  //去掉根节点
                fireDeviceVo.setPositionText(StringUtils.join(positionTextList, ">"));
            }
            if (positionCodeList.size() > 0) {
                Collections.reverse(positionCodeList);
                positionCodeList.remove(0);  //去掉根节点
                fireDeviceVo.setPositionCodeList(positionCodeList);
            }
        }
        return fireDeviceVo;
    }


    private FireDeviceVo entityToVo(FireDevice fireDevice,Map<Long,User> userMap,Map<String,DataDict> codeDataDictMap,Map<Long,DataDict> idDataDictMap) {
        FireDeviceVo fireDeviceVo = new FireDeviceVo();
        if(fireDevice == null){
            return fireDeviceVo;
        }
        BeanUtils.beanCopy(fireDevice, fireDeviceVo);

        //审核人
        Long auditUserId = fireDevice.getAuditUserId();
        if (auditUserId != null) {
            User user = userMap.get(auditUserId);
            if(user != null){
                fireDeviceVo.setAuditUserName(user.getUserName());
            }
        }
        if (StringUtils.isNotEmpty(fireDevice.getPosition())) {
            List<String> positionTextList = new ArrayList<>();
            List<String> positionCodeList = new ArrayList<>();
            DataDict dataDict = codeDataDictMap.get(fireDevice.getPosition());
            while (dataDict != null) {
                positionTextList.add(dataDict.getName());
                positionCodeList.add(dataDict.getCode());
                dataDict = idDataDictMap.get(dataDict.getParentId());
            }
            if (positionTextList.size() > 0) {
                Collections.reverse(positionTextList);
                positionTextList.remove(0);  //去掉根节点
                fireDeviceVo.setPositionText(StringUtils.join(positionTextList, ">"));
            }
            if (positionCodeList.size() > 0) {
                Collections.reverse(positionCodeList);
                positionCodeList.remove(0);  //去掉根节点
                fireDeviceVo.setPositionCodeList(positionCodeList);
            }
        }
        return fireDeviceVo;
    }





    public FireDeviceVo entityToFullVo(FireDevice fireDevice, Map<String,DataDict> deviceTypeDataDictMap,Map<Long,User> userMap,Map<String,DataDict> codeDataDictMap,Map<Long,DataDict> idDataDictMap) {
        FireDeviceVo fireDeviceVo = this.entityToVo(fireDevice,userMap,codeDataDictMap,idDataDictMap);
        Integer type = fireDevice.getType();
//        DataDict dataDict = dataDictService.getCodeLikeAndValue("0026", type.toString());
        DataDict dataDict = deviceTypeDataDictMap.get(type.toString());
        fireDeviceVo.setTypeText(dataDict.getName());

        Integer status = fireDevice.getStatus();
        DeviceAuditRecordStatusEnum statusEnum = DeviceAuditRecordStatusEnum.getByCode(status);
        fireDeviceVo.setStatusText(statusEnum.getValue());

        return fireDeviceVo;
    }

    public FireDeviceVo entityToFullVo(FireDevice fireDevice) {
        FireDeviceVo fireDeviceVo = this.entityToVo(fireDevice);
        Integer type = fireDevice.getType();
        DataDict dataDict = dataDictService.getCodeLikeAndValue("0026", type.toString());
        fireDeviceVo.setTypeText(dataDict.getName());

        Integer status = fireDevice.getStatus();
        DeviceAuditRecordStatusEnum statusEnum = DeviceAuditRecordStatusEnum.getByCode(status);
        fireDeviceVo.setStatusText(statusEnum.getValue());

        return fireDeviceVo;
    }


    @Transactional
    public void audit(Long id, Integer status, FireDeviceAuditParam param) {
        Long loginUserId = OnlineUserManager.getLoginUser().getUserId();
        //获取最近的任务对象
        FireDeviceAuditRecordQuery fireDeviceAuditRecordQuery = new FireDeviceAuditRecordQuery();
        fireDeviceAuditRecordQuery.setDeviceId(id);
        fireDeviceAuditRecordQuery.setResultLimit(1);
        FireDeviceAuditRecord fireDeviceAuditRecord = fireDeviceAuditRecordService.findOne(fireDeviceAuditRecordQuery);
        if (fireDeviceAuditRecord != null) {

            fireDeviceAuditRecord.setStatus(status);
            fireDeviceAuditRecord.setMemo(param.getMemo());
            fireDeviceAuditRecord.setAuditUserId(loginUserId);
            fireDeviceAuditRecord.setGmtAudit(new Date());
            fireDeviceAuditRecordService.update(fireDeviceAuditRecord);

            FireDevice fireDevice = this.findById(id);
            //保留code,不能被修改
            String code = fireDevice.getCode();
            BeanUtils.beanCopy(param,fireDevice);
            fireDevice.setCode(code);
            fireDevice.setGmtAudit(new Date());
            fireDevice.setStatus(status);
            fireDevice.setAuditUserId(OnlineUserManager.getLoginUser().getUserId());
            this.update(fireDevice);
        } else {
            throw new BizException("暂无扫描记录");
        }
    }

    public String getPrintHtml(FireDeviceQuery query) {
        long total = this.count(query);
        if (total > 1000) {
            throw new BizException("批量打印不能大于1000");
        }
        List<FireDevice> dataList = this.findAll(query);
        List<QrPrintPageVo> resultList = new ArrayList<>();
        int rowCount = 4;
        int rowIndex = 0;
        int lineCount = 5;
        int lineIndex = 1;
        List<QrPrintItemVo> itemList = new ArrayList<>();
        List<List<QrPrintItemVo>> pageItemList = new ArrayList<>();
        pageItemList.add(itemList);
        QrPrintPageVo qrPrintPageVo = new QrPrintPageVo();
        qrPrintPageVo.setItemList(pageItemList);
        resultList.add(qrPrintPageVo);

        for (FireDevice fireDevice : dataList) {
            if (rowIndex == rowCount) {
                itemList = new ArrayList<>();
                pageItemList.add(itemList);
                rowIndex = 0;
                lineIndex++;
            }
            if(lineIndex == lineCount){
                pageItemList = new ArrayList<>();
                qrPrintPageVo = new QrPrintPageVo();
                qrPrintPageVo.setItemList(pageItemList);
                resultList.add(qrPrintPageVo);
                lineIndex = 0;
            }

            QrPrintItemVo qrPrintItemVo = new QrPrintItemVo();
            qrPrintItemVo.setCode(fireDevice.getCode());
            String enCode;
            try {
                enCode = URLEncoder.encode(fireDevice.getCode(), Charset.defaultCharset().toString());
            } catch (UnsupportedEncodingException e) {
               throw new BizException(e);
            }
            String content = "http://extinguisher.website/detail.php?code=" + enCode;
            BufferedImage bufferedImage = QrCodeUtil.generate(content, 300, 300);
            String imgBase64 = ImgUtil.toBase64(bufferedImage, "png");
            String imgBase64Prefix = "data:image/png;base64,";
            qrPrintItemVo.setImgBase64(imgBase64Prefix + imgBase64);
            itemList.add(qrPrintItemVo);
            rowIndex++;
        }
        Context context = new Context();
        context.setVariable("resultList", resultList);
        String result = templateEngine.process("public/template", context);
        return result;
    }

    public void export(FireDeviceQuery query, HttpServletResponse response) {
//        long total = this.count(query);
//        if (total > 30000) {
//            throw new BizException("批量导出不能大于30000");
//        }
        List<FireDevice> dataList = this.findAll(query);
        List<List<Object>> xlsDataList = new ArrayList<>();
        xlsDataList.add(new ArrayList<>());
        xlsDataList.add(new ArrayList<>());
//        xlsDataList.add(Arrays.asList(headers));
        int orderNo = 1;
        Map<String,DataDict> deviceTypeDataDictMap = new HashMap<>();
        Map<Long,User> userMap = new HashMap<>();
        Map<String,DataDict> codeDataDictMap = new HashMap<>();
        Map<Long,DataDict> idDataDictMap = new HashMap<>();
//        DataDictQuery dataDictQuery = new DataDictQuery();
//        dataDictQuery.setCodeLike("0026");
        List<DataDict> dataDictList = dataDictService.findAll(new DataDictQuery());

        for (DataDict dataDict : dataDictList) {
            codeDataDictMap.put(dataDict.getCode(),dataDict);
            idDataDictMap.put(dataDict.getId(),dataDict);
            if(!dataDict.getCode().startsWith("0026")){
                continue;
            }
            deviceTypeDataDictMap.put(dataDict.getValue(),dataDict);
        }
        List<User> userList = userService.findAll(new UserQuery());
        for (User user : userList) {
            userMap.put(user.getId(),user);
        }

        if (CollectionUtils.isNotEmpty(dataList)) {
            for (FireDevice entity : dataList) {
                FireDeviceVo fireDeviceVo = this.entityToFullVo(entity,deviceTypeDataDictMap,userMap,codeDataDictMap,idDataDictMap);

                List<Object> rowList = new ArrayList<>();
                rowList.add("" + orderNo);
                rowList.add(fireDeviceVo.getCode());
                rowList.add(fireDeviceVo.getTypeText());
                rowList.add(fireDeviceVo.getPositionText());
                String gmtBuildStr = "";
                if (fireDeviceVo.getGmtBuild() != null) {
                    gmtBuildStr = DateFormatUtils.format(fireDeviceVo.getGmtBuild(), "yyyy-MM");
                }
                rowList.add(gmtBuildStr);
                rowList.add(fireDeviceVo.getStatusText());
                rowList.add(fireDeviceVo.getAuditUserName());
                String gmtAuditStr = "";
                if (fireDeviceVo.getGmtAudit() != null) {
                    gmtAuditStr = DateFormatUtils.format(fireDeviceVo.getGmtAudit(), "yyyy-MM-dd HH:mm:ss");
                }
                rowList.add(gmtAuditStr);
                rowList.add(fireDeviceVo.getArea());
                rowList.add(fireDeviceVo.getWeightType());
                rowList.add(fireDeviceVo.getMemo());
                xlsDataList.add(rowList);
                orderNo++;
            }
        }
        try {
            InputStream templateInputStream = deviceXlsTemplate.getInputStream();
            XlsUtils.export(xlsDataList, "消防检查设备汇总表", templateInputStream, response);
        } catch (Exception e) {
            throw new BizException(e);
        }

    }

    @Transactional
    public void readXls(InputStream inputStream) {
        List<FireDeviceExcelVo> list = EasyExcel.read(inputStream).head(FireDeviceExcelVo.class).sheet().doReadSync();
        for (FireDeviceExcelVo data : list) {
            FireDevice fireDevice = BeanUtils.beanCopy(data, FireDevice.class);
            String code = fireDevice.getCode();
            logger.info("code={}",code);
            code = code.replaceAll("–", "-");
            fireDevice.setCode(code);
            //导入，根据编码进行覆盖，如果没有就新增
            FireDevice dbFireDevice = this.findRawByCode(fireDevice.getCode());
            if(dbFireDevice != null){
                BeanUtils.beanCopy(fireDevice,dbFireDevice);
                this.update(dbFireDevice);
            }else{
                fireDevice.setStatus(DeviceAuditRecordStatusEnum.NOT_AUDIT.getCode());
                this.save(fireDevice);
            }
        }
    }

    @Transactional
    public void updateBuildTime(FireDeviceQuery query) {
        long total = this.count(query);
        if (total > 1000) {
            throw new BizException("批量修改生产日期的设备不能大于1000");
        }
        List<FireDevice> dataList = this.findAll(query);
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
//        if(dataList.size() > 1000){
//            throw new BizException("批量修改生产日期的设备不能大于1000");
//        }
        for (FireDevice fireDevice : dataList) {
//            Date date = LocalDateTimeUtils.convertLDToDate(query.getGmtBuildUpdate());
            fireDevice.setGmtBuild(query.getGmtBuildUpdate());
            //干粉、二氧化碳 过期日期自动+5年
            if (fireDevice.getType() == 1 || fireDevice.getType() == 2) {
                Date gmtExpire = DateUtils.addYears(query.getGmtBuildUpdate(), 5);
                fireDevice.setGmtExpire(gmtExpire);
            }
            this.update(fireDevice);
        }

    }

}
